OpenGL中的图像变换主要用四种:
1 | 1. 视角(Viewing)变换 |
视角变换
视角变换相当于人拿着一台照相机在观察物体,照相机在移动,从不同的位置来观察。具体的有以下三种变换:
1 | - Translate 平移变换 |
平移变换
在之前绘制的图形的代码的基础上,添加以下代码:
1 | //设置为单位矩阵 |
在平移变换之前,需调用glLoadIdentity才能进行变换,不加时图像不会显示。同时,在两句代码在onDrawFrame的任何位置,包括在清屏前都是没有影响的。
旋转变换
调用glRotatef(float angle, float x, float y, float z)传入4个参数,角度和x、y、z坐标。此时一定要注意旋转的角度,角度为正表示逆时针。
1 | gl.glLoadIdentity(); |
这里的x,y和z不是旋转的坐标点,而是向量点,即以(0,0,0)和(1,0,0)为一条线作为旋转的轴,轴的方向向(1,0,0),图像按这个轴进行旋转。旋转的方法遵循安培定则,即右手螺旋定则。用右手大拇指指向轴的正方向,其余手指卷曲的方向为旋转的方向。
glLoadIdentity在旋转中也不能少,不能会每次刷新时都会一直旋转,导致图像一直在移动。
缩放变换
调用glScalef(float x, float y, float z)进行缩放,三个参数为缩放比例,缩放之前的坐标乘以缩放比例即可。
1 | gl.glLoadIdentity(); |
glLoadIdentity的规则跟平移时一样。
组合变换
1 | gl.glLoadIdentity(); |
这边有个很关键的点,先平移后缩放,跟先缩放后平移效果是不一样的,而且实际变换的顺序跟逻辑执行的顺序刚好相反。
重置矩阵
如果想重置矩阵为没有任何变换之前,调用glLoadIdentity()
1 | gl.glLoadIdentity(); |
保存、恢复矩阵
调用glPushMatrix保存当前矩阵,调用glPopMatrix恢复当前矩阵。
1 | //保存当前矩阵 |
保留矩阵相当于把当前的矩阵记录了下来,在保留矩阵之后做的任何变换,在恢复矩阵时都是无效的,依旧会是保留时的矩阵数据。
模型变换
模型变换相当于是相机不动,而观察的物体在做移动,产生的效果跟视角变换是一样的。
投影变换
投影变换相当于观察物体是照相机的远近具体在发生变换。
投影变换会定义一个视锥(viewing volume),视锥有两个作用:
1 | - 物体如何投影到屏幕(透视投影或者正侧投影) |
OpenGL ES可以使用两种不同的投影变换:透视投影(Perspective Projection)和正侧投影(Orthographic Projection)。
透视投影
透视投影 ,就像我们眼睛看一个物体,近大远小。 如下图:
从照相机(View Point)望去,由left、top、bottom、right四条线组成的面(也就是near面)和最远处的面(也就是far面)组成了一个椎体,这个椎体叫View volumn。
裁剪就是把Viewing Volume之外的都裁剪掉,这样可以提高绘图性能。
public void glFrustumf(float left,float right,float bottom,float top,float near,float far)
也可以用GLU.gluPerspective(fovy, aspect, zNear, zFar)方法,fovy是竖直方向也就是Y方向的夹角,aspect是near面的宽高比,即top的长度除以left长度。
正侧投影
正侧投影 ,View Volumn椎体不变,一直是一个长方体,无论距离怎么改变,投影都不变。相当于透视投影,眼睛是一个点,而正侧投影,眼睛是一个面。
定义正侧投影的方法如下,传入6个参数
public void glOrthof(float left, float right,float bottom,float top,float near,float far)
视窗变换
视窗变换相当于物体和相机都没有变换,但是出来的效果之后,显示这个的载体发生了变化。
把像素按照比例转化后显示到屏幕上,这就是视窗(Viewport)变换,分两步
1 | - 设置窗口的位置和大小————glViewport(int x, int y, int width, int height) |
第一种就是onSurfaceChanged
1 |
|
设置观察的位置和角度
GLU.gluLookAt(gl, eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ)
1 | - eye理解为照相机或者你的眼睛,默认位置在原点(0,0,0) |
默认情况下,一个物体的观察坐标是:
1 | GLU.gluLookAt(gl, 0f, 0f, 0f, 0f, 0f, -1f, 0f, 1f, 0f); |
即眼睛和物体都在x和y的原点,z轴上,眼睛在0,物体在-1,而y轴也是正着的。
如果改为:
1 | GLU.gluLookAt(gl, 0f, 0f, 0f, 0f, 0f, -1f, 1f, 0f, 0f) |
就相当于侧着头看,而且是沿着x轴的正方向看。
实际的效果是,如果在屏幕的左上角绘制一个图像,那么侧着看的话,图像就在屏幕的左下方了。